//===--- NecessaryBindings.h - Optimizing archetype bindings ----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines a utility class for saving and restoring the
// archetype metadata necessary in order to carry out value operations
// on a type.
//
// This is a supplemental API of GenProto.
//
//===----------------------------------------------------------------------===//

#ifndef POLARPHP_IRGEN_INTERNAL_NECESSARYBINDINGS_H
#define POLARPHP_IRGEN_INTERNAL_NECESSARYBINDINGS_H

#include "polarphp/irgen/internal/GenericRequirement.h"
#include "llvm/ADT/SetVector.h"
#include "polarphp/ast/Types.h"

namespace polar {
class CanType;
enum class MetadataState : size_t;
class InterfaceDecl;
class InterfaceConformanceRef;

namespace irgen {
class Address;
class IRGenFunction;
class IRGenModule;
class Size;

/// NecessaryBindings - The set of metadata that must be saved in
/// order to perform some set of operations on a type.
class NecessaryBindings {
   llvm::SetVector<GenericRequirement> Requirements;

public:
   NecessaryBindings() = default;

   /// Collect the necessary bindings to invoke a function with the given
   /// signature.
   static NecessaryBindings forFunctionInvocations(IRGenModule &IGM,
                                                   CanPILFunctionType origType,
                                                   SubstitutionMap subs);

   /// Add whatever information is necessary to reconstruct type metadata
   /// for the given type.
   void addTypeMetadata(CanType type);

   /// Get the requirement from the bindings at index i.
   const GenericRequirement &operator[](size_t i) const {
      return Requirements[i];
   }

   size_t size() const {
      return Requirements.size();
   }

   /// Add whatever information is necessary to reconstruct a witness table
   /// reference for the given type.
   void addInterfaceConformance(CanType type, InterfaceConformanceRef conf);

   /// Is the work to do trivial?
   bool empty() const { return Requirements.empty(); }

   /// Returns the required size of the bindings.
   /// Pointer alignment is sufficient.
   Size getBufferSize(IRGenModule &IGM) const;

   /// Save the necessary bindings to the given buffer.
   void save(IRGenFunction &IGF, Address buffer) const;

   /// Restore the necessary bindings from the given buffer.
   void restore(IRGenFunction &IGF, Address buffer, MetadataState state) const;

   const llvm::SetVector<GenericRequirement> &getRequirements() const {
      return Requirements;
   }
};

} // end namespace irgen
} // end namespace polar

#endif // POLARPHP_IRGEN_INTERNAL_NECESSARYBINDINGS_H
